package com.hnyc.token.impl;

import com.alibaba.fastjson2.JSONObject;
import com.hnyc.config.ShopeeConfig;
import com.hnyc.shopee.ShopeeAuthException;
import com.hnyc.shopee.domain.AccessTokenResp;
import com.hnyc.shopee.domain.RefreshTokenResp;
import com.hnyc.token.ITokenService;
import com.ruoyi.common.constant.HttpStatus;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @auther zero
 * @date 2023/3/11
 **/
@Service("shopee")
@Slf4j
@Data
public class ShopeeTokenServiceImpl implements ITokenService {
OkHttpClient client=new OkHttpClient.Builder()
        .protocols(Collections.singletonList(Protocol.HTTP_1_1))
        .callTimeout(30, TimeUnit.SECONDS)
        .readTimeout(10,TimeUnit.SECONDS).build();
    @Resource
    ShopeeConfig shopeeConfig;
    @Override
    public AccessTokenResp getShopToken( String code,long shopId) {
        return getToken(code,shopId,"shop_id");
    }
    public AccessTokenResp getToken( String code,long shopId,String typeKey) {
        long timest = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/auth/token/get";
        String tmp_base_string = String.format("%s%s%s", shopeeConfig.getPartnerId(), path, timest);
        byte[] partner_key;
        byte[] base_string;
        BigInteger sign = null;

        try {
            base_string = tmp_base_string.getBytes("UTF-8");
            partner_key = shopeeConfig.getPartnerKey().getBytes("UTF-8");
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
            mac.init(secret_key);
            sign = new BigInteger(1, mac.doFinal(base_string));
        } catch (Exception e) {
            e.printStackTrace();
        }
        String tmp_url = shopeeConfig.getHost() + path + String.format("?partner_id=%s&timestamp=%s&sign=%s", shopeeConfig.getPartnerId(), timest, String.format("%032x", sign));

        RequestBody requestBody = RequestBody.create(
                MediaType.parse("application/json"),
                JSONObject.of("code", code,
                        "partner_id", shopeeConfig.getPartnerId(),
                        typeKey,shopId).toString()
                );
        Request req = new Request.Builder()
                .url(tmp_url)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .post(requestBody)
                .build();
        try {
            Response resp = client.newCall(req).execute();
            if (resp.code() == 200) {
                String respStr = IOUtils.toString(resp.body().byteStream(), StandardCharsets.UTF_8);
                log.info(respStr);
                AccessTokenResp accessTokenResp = JSONObject.parseObject(respStr, AccessTokenResp.class);
                return  accessTokenResp;
            }else if(resp.code()== HttpStatus.FORBIDDEN){
                log.error("code 已过期，请重新请求code");
            }
            throw new ShopeeAuthException(resp.message());
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new ShopeeAuthException("unknonw error");
    }

    @Override
    public AccessTokenResp getAccountToken(String code, long mainAccountId) {
        // 主账号级别的，会返回shopid list 和 merchant list
        return getToken(code,mainAccountId,"main_account_id");
    }


    //shop request for access token for the first time
//    public String[] get_token_shop_level(String code, long partner_id, String tmp_partner_key, long shop_id) throws ParseException, IOException {
//        String[] res = new String[2];
//        long timest = System.currentTimeMillis() / 1000L;
//
//        String path = "/api/v2/auth/token/get";
//        String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
//        byte[] partner_key;
//        byte[] base_string;
//        BigInteger sign = null;
//        String result = "";
//        try {
//            base_string = tmp_base_string.getBytes("UTF-8");
//            partner_key = tmp_partner_key.getBytes("UTF-8");
//            Mac mac = Mac.getInstance("HmacSHA256");
//            SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
//            mac.init(secret_key);
//            sign = new BigInteger(1, mac.doFinal(base_string));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        String tmp_url = shopeeConfig + path + String.format("?partner_id=%s&timestamp=%s&sign=%s", partner_id, timest, String.format("%032x", sign));
//        URL url = new URL(tmp_url);
//        HttpURLConnection conn = null;
//        PrintWriter out = null;
//        BufferedReader in = null;
//        try {
//            conn = (HttpURLConnection) url.openConnection();
//            conn.setRequestMethod("POST");
//            conn.setDoOutput(true);
//            conn.setDoInput(true);
//            conn.setConnectTimeout(30000);
//            conn.setReadTimeout(10000);
//            conn.setRequestProperty("Content-Type", "application/json");
//            conn.setRequestProperty("Accept", "application/json");
//            Map<String, Object> map = new HashMap<>();
//            map.put("code", code);
//            map.put("shop_id", shop_id);
//            map.put("partner_id", partner_id);
//            String json = JSON.toJSONString(map);
//            conn.connect();
//            out = new PrintWriter(conn.getOutputStream());
//            out.print(json);
//            out.flush();
//            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
//            String line = "";
//            while ((line = in.readLine()) != null) {
//                result += line;
//            }
//            JSONObject jsonObject = JSONObject.parseObject(result);
//            res[0] = (String) jsonObject.get("access_token");
//            res[1] = (String) jsonObject.get("refresh_token");
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                if (out != null) {
//                    out.close();
//                }
//                if (in != null) {
//                    in.close();
//                }
//            } catch (IOException ioe) {
//                ioe.printStackTrace();
//            }
//        }
//        return res;
//    }
    @Override
    public RefreshTokenResp refreshShopToken(String refreshToken,long shopId) {
        return refreshToken(refreshToken,shopId,"shop_id");
    }
    public RefreshTokenResp refreshToken(String refreshToken,long shopId,String typeKey) {


        long timest = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/auth/access_token/get";
        String tmp_base_string = String.format("%s%s%s", shopeeConfig.getPartnerId(), path, timest);
        byte[] partner_key;
        byte[] base_string;
        BigInteger sign = null;

        try {
            base_string = tmp_base_string.getBytes("UTF-8");
            partner_key =  shopeeConfig.getPartnerKey().getBytes("UTF-8");
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
            mac.init(secret_key);
            sign = new BigInteger(1,mac.doFinal(base_string));
        } catch (Exception e) {
            e.printStackTrace();
        }
        String tmp_url = shopeeConfig.getHost() + path + String.format("?partner_id=%s&timestamp=%s&sign=%s",  shopeeConfig.getPartnerId(),timest, String.format("%032x",sign));

        JSONObject param = JSONObject.of(
                typeKey, shopId,
                "partner_id", shopeeConfig.getPartnerId(),
                "refresh_token", refreshToken);
        RequestBody requestBody = RequestBody.create(
                MediaType.parse("application/json"),
                param.toString()
               );
        Request req = new Request.Builder()
                .url(tmp_url)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .post(requestBody)
                .build();
        try {
            Response resp = client.newCall(req).execute();
            if (resp.code() == 200) {
                String json = IOUtils.toString(resp.body().byteStream(), StandardCharsets.UTF_8);
                log.info("refresh json:{}",json);
                RefreshTokenResp accessTokenResp = JSONObject.parseObject(json, RefreshTokenResp.class);
                return  accessTokenResp;
            }
            throw new ShopeeAuthException(resp.message());
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new ShopeeAuthException("unknonw error");

    }

    @Override
    public RefreshTokenResp refreshAccountToken(String refreshToken, long merchantId) {
        // 主账号维度，没有刷新token机制，只有merchant级别的
        return refreshToken(refreshToken,merchantId,"merchant_id");
    }

//    public String[] get_access_token_shop_level(String refresh_token) throws ParseException,IOException{
//        long partner_id = shopeeConfig.getPartnerId();
//        String tmp_partner_key = shopeeConfig.getPartnerKey();
//        long shop_id = shopeeConfig.getShopId();
//        String[] res = new String[2];
//        long timest = System.currentTimeMillis() / 1000L;
//        String path = "/api/v2/auth/access_token/get";
//        String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
//        byte[] partner_key;
//        byte[] base_string;
//        BigInteger sign = null;
//        String result = "";
//        try {
//            base_string = tmp_base_string.getBytes("UTF-8");
//            partner_key = tmp_partner_key.getBytes("UTF-8");
//            Mac mac = Mac.getInstance("HmacSHA256");
//            SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
//            mac.init(secret_key);
//            sign = new BigInteger(1,mac.doFinal(base_string));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        String tmp_url = shopeeConfig.getHost() + path + String.format("?partner_id=%s&timestamp=%s&sign=%s", partner_id,timest, String.format("%032x",sign));
//        URL url = new URL(tmp_url);
//        HttpURLConnection conn = null;
//        PrintWriter out = null;
//        BufferedReader in = null;
//        try {
//            conn = (HttpURLConnection) url.openConnection();
//            conn.setRequestMethod("POST");
//            conn.setDoOutput(true);
//            conn.setDoInput(true);
//            conn.setConnectTimeout(30000);
//            conn.setReadTimeout(10000);
//            conn.setRequestProperty("Content-Type", "application/json");
//            conn.setRequestProperty("Accept", "application/json");
//            Map<String,Object> map = new HashMap<>();
//            map.put("refresh_token",refresh_token);
//            map.put("shop_id",shop_id);
//            map.put("partner_id",partner_id);
//            String json = JSON.toJSONString(map);
//            conn.connect();
//            out = new PrintWriter(conn.getOutputStream());
//            out.print(json);
//            out.flush();
//            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
//            String line = "";
//            while((line=in.readLine())!=null){
//                result +=line;
//            }
//            JSONObject jsonObject = JSONObject.parseObject(result);
//            res[0] = (String) jsonObject.get("access_token");
//            res[1] = (String) jsonObject.get("refresh_token");
//        } catch(Exception e){
//            e.printStackTrace();
//        }finally {
//            try{
//                if(out != null){
//                    out.close();
//                }
//                if(in != null){
//                    in.close();
//                }
//            }catch (IOException ioe){
//                ioe.printStackTrace();
//            }
//        }
//        return res;
//    }
}
